package physicsModeler;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Timer;

import physicsModeler.environment.DrawEnvironment;
import physicsModeler.objects.DrawObject;
import physicsModeler.Vector;


public class Handler implements KeyListener 
{
	
	ObjectFactory objectFactory;
	EnvironmentFactory environmentFactory;
	DrawObject drawActiveObject;
	DrawEnvironment drawStaticObject;
	DrawToolBar UI;
	Screen screen;
	private String exit = "Press esc to exit!";
	
	private int SCALAR_MULTIPLIER = 5;
	Thread animationThread;
	Thread drawThread; 
	
	boolean run = true;
	double prevTime, curTime;
	double prevXDist, curXDist, prevYDist, curYDist;
	
	// Draw Object collections
	ArrayList<DrawObject> myActiveObjects = new ArrayList<DrawObject>();
	ArrayList<DrawEnvironment> myStaticObjects = new ArrayList<DrawEnvironment>();
	
	// int testx = 20, testy = 300;
	// common display modes(more will be added for greater resolution)/////////
	
	public Handler()
	{
		objectFactory = new ObjectFactory();
		environmentFactory = new EnvironmentFactory();
		
	}
	
	public Screen getScreen() {
		return screen;
	}

	public void setScreen(Screen screen) {
		this.screen = screen;
	}

	
	
	
	
	private static final DisplayMode possibleModes[] = {
		new DisplayMode(1440,900,32,0),
		new DisplayMode(800, 600, 32, 0),
		new DisplayMode(800, 600, 24, 0),
		new DisplayMode(800, 600, 16, 0),
		new DisplayMode(640, 480, 32, 0),
		new DisplayMode(640, 480, 24, 0),
		new DisplayMode(640, 480, 16, 0),
		
	};
	///////////////////////////////////////////////////////////////////////////
	
	public void Inititialize() 
	{
		// .. This is where I'd imagine we load images(sprites) and set any static values
		Window window = screen.getFullScreenWindow();
		window.addKeyListener(this);
		addMouse(window);
		// objectFactory = new ObjectFactory();
		//UI = new DrawToolBar();
	}
	
	public void Run()
	{

		screen = new Screen();
		
		
		try
		{
			DisplayMode displayMode = screen.FindCompatibleMode(possibleModes); // this is where we find our screen
			screen.setFullScreen(displayMode);
			UI = new DrawToolBar(screen);
			UI.loadUIObjects(objectFactory,environmentFactory);
			
			Inititialize();
			GameLoop(); // Coded in here is everything that changes(logic, redrawing, etc...)
		}
		finally 
		{
			screen.RestoreScreen();
		}
		
	}
	
	public void Draw(Graphics2D graphics)
	{
//		.. Draws images defined by a board or environment class	
		graphics.clearRect(0, 0, screen.getWidth(), screen.getHeight()); // Needed to clear previous screen
		
		try 
		{
			//objectFactory.createDrawObject("Ball");
			
			/*Use below method call for UI list */
			// objectFactory.createDrawObject(UI.getObjItem());
		} 
		catch (Exception e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//			.. Draws images defined by a board or environment class	
		graphics.clearRect(0, 0, screen.getWidth(), screen.getHeight()); // Needed to clear previous screen
		
		//graphics.drawString("Alive: " + testShape.size(), 50, 50);
		//graphics.drawString("Dead : " + deadShape.size(), 50, 63);
		
		
	}
	
	public void Animate()
	{
		// testx++;
		// testy++;
	}
	
	public void GameLoop()
	{
	long milliseconds,secondsElapsed;
	double avgFPS =  0.0;
	
		while (run) // For now we can manually tell the game to stop using esc key or something
		{
			milliseconds = System.currentTimeMillis();
			Graphics2D graphics = screen.getGraphics();
			//Animate();
			Draw(graphics);
			UI.Draw(graphics,avgFPS);
			ArrayList<DrawObject> screenActiveObjects = (ArrayList<DrawObject>) myActiveObjects.clone();
			ArrayList<DrawEnvironment> screenStaticObjects = (ArrayList<DrawEnvironment>) myStaticObjects.clone();
			
			for(DrawObject object: screenActiveObjects)
			{
				object.draw(graphics);
			}
			
			for(DrawEnvironment object: screenStaticObjects)
			{
				object.draw(graphics);
			}
			
			graphics.dispose(); // garbage
			screen.update();
			long nowtime = System.currentTimeMillis();
			secondsElapsed = nowtime - milliseconds;
			//avgFPS = (100 / secondsElapsed) ;
			avgFPS = (1 / (secondsElapsed + .03));
			try 
			{
				Thread.sleep(20);
			} catch (Exception exception) {}
			
		}
	}
	
	public void stop() { run = false; }

	@Override
	public void keyPressed(KeyEvent event) 
	{
		// TODO Auto-generated method stub
		int key = event.getKeyCode();
		if (key == KeyEvent.VK_ESCAPE)
			stop();
	
			
		
	}

	@Override
	public void keyReleased(KeyEvent event) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent event) {
		// TODO Auto-generated method stub
		
	}
	
	private void addMouse(Window window) 
	{
		window.addMouseListener(new MouseAdapter()
		{
			Vector mouseVector = new Vector();
			public void mousePressed(MouseEvent mouseEvent)
			{
				Map<String,String> UISelection = new HashMap<String,String>();
				String category,name;
				
				// run = false;
				try {
					
					
					UISelection = UI.checkItemSelected(mouseEvent.getXOnScreen(), mouseEvent.getYOnScreen());
					if(UISelection != null)
					{
						Set keySet = UISelection.keySet();
						Iterator i = keySet.iterator();
						category = (String)i.next();
						name = UISelection.get(category);
						if(category == "ActiveObject")
						{
							drawActiveObject = (DrawObject)objectFactory.createDrawObject(name);
							drawActiveObject.setPositionX(mouseEvent.getXOnScreen());
							drawActiveObject.setPositionY(mouseEvent.getYOnScreen());
							myActiveObjects.add(drawActiveObject);
						}
						else
						{
							drawStaticObject = (DrawEnvironment)environmentFactory.createDrawEnvironment(name);
							drawActiveObject.setPositionX(mouseEvent.getXOnScreen());
							drawActiveObject.setPositionY(mouseEvent.getYOnScreen());
							myStaticObjects.add(drawStaticObject);
						}
						
					}
					
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				currentValues(mouseEvent);
				// testShape.add(new drawObject("Circle", mouseEvent.getX(), mouseEvent.getY(), 20, findMouseVector()));
				
				previousValues(mouseEvent);
				
				// run = true;
				// GameLoop();
			}
			
			private void currentValues(MouseEvent mouseEvent)
			{
				curTime = System.currentTimeMillis();
				curXDist = mouseEvent.getX();
				curYDist = mouseEvent.getY();
			}
			
			private void previousValues(MouseEvent mouseEvent)
			{
				prevTime = System.currentTimeMillis();
				prevXDist = mouseEvent.getX();
				prevYDist = mouseEvent.getY();
			}
			
			private Vector findMouseVector()
			{
				mouseVector.setCoordinates(((curXDist - prevXDist) * SCALAR_MULTIPLIER) / (curTime - prevTime),
						                   ((curYDist - prevYDist) * SCALAR_MULTIPLIER) / (curTime - prevTime));
				
				return mouseVector;
			}

	     });
	}
}
